/*
*  logging.c - log/cache data
*  Copyright (c) 2008 Derek Ingrouville (dergro@users.sourceforge.net)
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Library General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include <glib.h>

#ifdef _W32_
#include <windows.h>
#endif

#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include "logging.h"

#ifdef _W32_
#define nl "\r\n"
#else
#define nl "\n"
#endif

/* TODO: This would be sooo much cleaner with fgets and fputs */
/* TODO: This code is disgusting */

int log_init (struct log_data *ld, const char *dir, const char *file)
{
    char   *path = NULL, *delim = NULL;

    g_return_val_if_fail (ld != NULL, -1);
    g_return_val_if_fail (dir != NULL, -1);
    g_return_val_if_fail (file != NULL, -1);

#ifdef _W32_
    delim = "\\";
#else
    delim = "/";
#endif

    if (g_str_has_suffix (dir, delim))
        path = g_strconcat (dir, file, NULL);
    else
        path = g_strconcat (dir, delim, file, NULL);

    if (!fopen (path, "a")) {
        /* Couldn't open the directory, so we'll try to create it */

#ifdef _W32_			/* Are we using Windows? */
        if (!CreateDirectory (dir, NULL))
            g_printerr ("Failed to create dir %s\n", dir);

#else
        if (mkdir (dir, S_IREAD | S_IRGRP | S_IROTH | S_IWRITE | S_IEXEC) ==
            -1)
            perror (NULL);
#endif

        /* try again... */
        if (!fopen (path, "a"))
            return -1;
    }
    ld->path = path;
    ld->dir = g_strdup (dir);
    ld->file = g_strdup (file);

    return 0;
}

/* My apologies for this function :( */
int cache_value (struct log_data *ld, const char *key, const char *value)
{
    char   *buf = NULL, **sb_n = NULL, **sb_c = NULL;
    int     size, i = 0, x = 0, found = 0;
    GError *g_err = NULL;
    FILE   *fp = NULL;

    g_return_val_if_fail (ld != NULL, -1);
    g_return_val_if_fail (key != NULL, -1);
    g_return_val_if_fail (value != NULL, -1);

    /** Read and parse the contents of the file **/
    g_file_get_contents (ld->path, &buf, (gsize *) & size, &g_err);
    sb_n = g_strsplit (buf, nl, 0);

    while (sb_n[i] != NULL) {
        if (strlen (sb_n[i]) >= 3) {
            sb_c = g_strsplit (sb_n[i], "=", 0);

            for (x = 0; x < 2; x++) {
                if (strlen (sb_c[x]) > 1) {
                    if (x == 0 && (strcmp (sb_c[x], key) == 0)) {
                        if (strcmp (sb_c[++x], value) != 0) {
                            g_free ((gpointer) sb_c[x]);
                            sb_c[x] = g_strdup (value);
                        }
                        found = 1;
                    }
                }
            }

            if (found) {
                g_free ((gpointer) sb_n[i]);
                sb_n[i] = g_strconcat (sb_c[0], "=", sb_c[1], NULL);
                g_strfreev (sb_c);
                ++i;
            } else {
                g_strfreev (sb_c);
                ++i;
            }
        } else
            ++i;
    }

    /** Open the file for writing **/
    fp = fopen (ld->path, "w");

    if (!fp) {
        g_printerr ("**ERROR** failed to open %s with mode a+", ld->path);
        return -1;
    }
    /** Write the previous contents of the file **/
    /** if KEY was found in the previous contents, it's value was changed **/
    /** and the new value will be writen here */
    for (x = 0; x < i; x++) {
        if (sb_n[x] == NULL)
            break;
        else if (strlen (sb_n[x]) > 3) {
            fwrite (sb_n[x], sizeof (char), strlen (sb_n[x]), fp);
            fwrite (nl, sizeof (char), strlen (nl), fp);
        }
    }

    if (!found) {
        char   *tmp = g_strconcat (key, "=", value, nl, NULL);

        if (strlen (tmp) > 3) {
            fwrite (tmp, sizeof (char), strlen (tmp), fp);
            fwrite (nl, sizeof (char), strlen (nl), fp);
        }
        g_free ((gpointer) tmp);
    }

    g_free ((gpointer) buf);
    g_strfreev (sb_n);
    fclose (fp);

    return 1;
}


char *get_cached_value (struct log_data *ld, char *key)
{
    char   *buf = NULL, *ret_buf = NULL, **sb_n = NULL, **sb_c = NULL;
    int     size, i = 0, x = 0, found = 0;
    GError *g_err = NULL;

    g_return_val_if_fail (ld != NULL, NULL);
    g_return_val_if_fail (key != NULL, NULL);

    /** Read the contents of the file **/
    g_file_get_contents (ld->path, &buf, (gsize *) & size, &g_err);
    sb_n = g_strsplit (buf, "nl", 0);

    while (sb_n[i] != NULL) {
        if (strlen (sb_n[i]) >= 3) {
            sb_c = g_strsplit (sb_n[i++], "=", 0);

            for (x = 0; x < 2; x++) {
                if (strlen (sb_c[x]) > 1) {
                    if (x == 0 && !(strcmp (sb_c[x], key))) {
                        ret_buf = g_strdup (sb_c[++x]);
                        found = 1;
                    }
                }
            }

            g_strfreev (sb_c);

            if (found)
                break;
        } else
            ++i;
    }

    g_free ((gpointer) buf);
    g_strfreev (sb_n);

    return ret_buf;
}

void log_free (struct log_data *ld)
{
    g_return_if_fail (ld != NULL);

    if (ld->path != NULL)
        g_free ((gpointer) ld->path);

    if (ld->dir != NULL)
        g_free ((gpointer) ld->dir);

    if (ld->file != NULL)
        g_free ((gpointer) ld->file);

    return;
}
